/**
 * @file swei_status.c
 * @brief 设备状态信息包处理，主要预留对外接口用于触发状态信息包上传，主要通过事件触发进行，注意先更新数据再触发上报
 *          libat - 小电池
 *          libat_chg - 小电池充电
 *          fwver - 固件版本信息
 * @author henry.cai (henry.cai@queclink.com)
 * @version 1.0
 * @date 2024-09-12
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-12 <td>1.0     <td>        <td>设备状态信息包
 * </table>
 */
#include "include/port/swei_log.h"
#include "include/swei_status.h"
#include "include/swei_common.h"
#include "misc/misc_system.h"
#include "include/swei_package.h"
#include "utils/utils_timer.h"
#include "include/port/swei_fw_info.h"
#include "global.h"
#include "misc/version.h"
#include "utils/utils.h"
#include "comm/co_heartbeat.h"
#include "aadl/public.h"
#include "service/include/port/swei_version.h"
#include "service/include/port/swei_wrapper.h"

#include <stdio.h>

// 设备状态信息包主要分为几个类别:  1. 小电池信息; 2. 小电池充电信息; 3. 固件版本信息; 4.modem信号强度; 5.车端状态; 6.车端故障
// 不同于定位信息和告警信息，车端的小电池信息等信息不作为盲区数据存储，仅实时定期采集和上报;
// swei_status_update -> swei_status_get_info_api -> push to cache

#define TBOX_INFO_PACK(type, member)\
        swei_get_device_info(type, (void *)&member, sizeof(member))

// 状态值通用报文格式
typedef struct
{
    unsigned short status_id;
    unsigned short len;
    unsigned char data[256];
} UPLOAD_INFO_ST;

extern uint16_t ble_mac_get(uint8_t *p_data, uint16_t len);
extern uint16_t ble_version_get(uint8_t *p_data, uint16_t len);

errno_t memmove_s(void * dest, size_t destSize, const void * src, size_t count) {
    if (!dest || !src) {
        return EINVAL; // Invalid argument
    }

    if (destSize < count) {
        log_e("destSize is not enough! destSize=%d, count=%d", destSize, count);
        count = destSize; // copy destSize bytes at most
    }

    uint8_t *dest_ptr = (uint8_t *) dest;
    const uint8_t *src_ptr = (const uint8_t *) src;

    size_t i;
    if (src_ptr < dest_ptr && dest_ptr < src_ptr + count) {
        // Buffers overlap with dest_ptr higher than src_ptr, so copy backwards
        for (i = count; i > 0; --i) {
            dest_ptr[i - 1] = src_ptr[i - 1];
        }
    } else {
        // Either no overlap, or dest_ptr is lower than src_ptr, so copy forwards
        for (i = 0; i < count; ++i) {
            dest_ptr[i] = src_ptr[i];
        }
    }

    return SUCC; // Success
}


/**
 * @description:
 * @param {UPLOAD_INFO_ST} info
 * @param {common_msg_st} *msg
 * @return {*}
 * @Date: 2024-01-15 17:02:38
 * @modification:
 */
static int32_t info2msg(UPLOAD_INFO_ST info, common_msg_st *msg)
{
    if (msg == NULL)
    {
        log_e("info2msg input null pointer[msg]!\r\n");
        return -EPERM;
    }

    int32_t info_len = info.len;
    int32_t msg_len = msg->msg_len;

    if (msg_len + info_len + 4 >= MSG_CONTENT_LEN) {
        log_e("msg_len is not enough! msg_len=%d, len=%d\r\n");
        return -ENOMEM;
    }

    // info里面的数据是小端模式
    msg->msg_content[msg_len++] = (info.status_id >> 8) & 0xff;
    msg->msg_content[msg_len++] = info.status_id & 0xff;
    msg->msg_content[msg_len++] = (info.len >> 8) & 0xff;
    msg->msg_content[msg_len++] = info.len & 0xff;
    // 配置给 msg 数据
    memmove_s(msg->msg_content + msg_len, 
                    MSG_CONTENT_LEN - msg_len, info.data, info_len);

    return info_len + 4 ;
}


/**
 * @description: 获取小电池信息
 * @param {common_msg_st} *msg - output
 * @return {*}
 * @Date: 2023-12-22 16:24:52
 * @modification:
 */
int32_t swei_status_get_libat_info(common_msg_st *msg)
{
    libat_info_t libat_info;

    int32_t res = swei_get_device_info(LIBAT_INFO, (void *)&libat_info, sizeof(libat_info));    
    if (res != 0) {
        log_e("tbox get libat info failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;

    info.status_id = CAN_UPLOAD_TAG_ID_TBOX_BMS_INFO;
    info.data[info.len++] = ((int32_t)(libat_info.volt) >> 8) & 0xFF;
    info.data[info.len++] = ((int32_t)(libat_info.volt)) & 0xFF;
    info.data[info.len++] = ((int32_t)(libat_info.power)) & 0xFF;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_batt_info(common_msg_st *msg)
{
    batt_info_t batt_info = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(BATT_INFO, (void *)&batt_info, sizeof(batt_info));    
    if (res != 0)
    {
        log_e("tbox get batt info failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    info.status_id = CAN_UPLOAD_TAG_ID_TBOX_BMS_INFO;   
    info.data[idx ++] = ((batt_info.volt/10) >> 8) & 0xff;
    info.data[idx ++] = (batt_info.volt/10) & 0xff;
    info.data[idx ++] = batt_info.volt_percent;
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取小电池充电信息
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} type - 充电类型
 * @return {*}
 * @Date: 2023-12-22 16:24:52
 * @modification:
 */
int32_t swei_status_get_charger_info(common_msg_st *msg, uint8_t type)
{
    libat_charger_info_t libat_charger_info;
    /* 1. 获取小电池信息 */
    int32_t res = swei_get_device_info(LIBAT_CHARGER_INFO, (void *)&libat_charger_info, sizeof(libat_charger_info));    
    if (res != 0)
    {
        log_e("tbox get libat charge info failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    info.data[idx ++] = type; // 上报时机
    info.data[idx ++] = (libat_charger_info.charge_count >> 8) & 0xff;
    info.data[idx ++] = libat_charger_info.charge_count & 0xff;
    idx += bigending2buf(info.data + idx, libat_charger_info.charge_total_time);
    info.len = idx;

    // 3. 转化info为msg数据结构
        int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_dev_info(common_msg_st *msg)
{
    tbox_info_t tbox_info = {0};

    sscanf(MODEL, "T%s", &tbox_info.tbox_model);
    
    int32_t res = TBOX_INFO_PACK(ICCID_INFO, tbox_info.tbox_iccid);
    if (res != 0)
    {
        log_e("tbox get iccid info failed,res:%d", res);
        return -EIO;
    }  

    res = TBOX_INFO_PACK(IMEI_INFO_BCD, tbox_info.tbox_imei);
    if (res != 0)
    {
        log_e("tbox get imei info failed,res:%d", res);
        return -EIO;
    } 

    ble_mac_get(tbox_info.tbox_ble_mac, sizeof(tbox_info.tbox_ble_mac));
    if(!strlen((char *)tbox_info.tbox_ble_mac))
    {
        log_e("tbox get ble mac failed");
        return -EIO;        
    }

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_DEV_INFO;
    memcpy(info.data, &tbox_info, sizeof(tbox_info));
    info.len = sizeof(tbox_info);

    // 3. 转化info为msg数据结构
        int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_tbox_stat(common_msg_st *msg)
{
    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};
    int32_t idx = 0;

    info.status_id = CAN_UPLOAD_STATUS_INFO;
    info.data[idx++] = !is_ebike_mcu_off();
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


#include "service/include/port/swei_version.h"
int32_t swei_status_get_version_info(common_msg_st *msg)
{
    tbox_version_t co_version = {.version_type = 0x11};
    tbox_version_t bt_version = {.version_type = 0x13}; 
    tbox_version_t iot_version = {.version_type = 0x12}; 
    tbox_version_t soft_version = {.version = SWEI_SOFTWARE_VERSION, .version_type = 0x10};     
    int idx = 0;

    co_version_get((uint8_t *)co_version.version, sizeof(co_version.version));
    ble_version_get((uint8_t *)bt_version.version, sizeof(bt_version.version));
    strncpy(iot_version.version, SOFTWARE_VERSION, strlen(SOFTWARE_VERSION));
  
    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = TBOX_UPLOAD_DEV_VERSION;

    info.data[idx++] = soft_version.version_type;
    info.data[idx++] = strlen(soft_version.version);
    strncpy((char *)&info.data[idx], soft_version.version, strlen(soft_version.version));
    idx += strlen(soft_version.version);    

    info.data[idx++] = co_version.version_type;
    info.data[idx++] = strlen(co_version.version);
    strncpy((char *)&info.data[idx], co_version.version, strlen(co_version.version));
    idx += strlen(co_version.version);

    info.data[idx++] = iot_version.version_type;
    info.data[idx++] = strlen(iot_version.version);
    strncpy((char *)&info.data[idx], iot_version.version, strlen(iot_version.version));
    idx += strlen(iot_version.version);

    info.data[idx++] = bt_version.version_type;
    info.data[idx++] = strlen(bt_version.version);
    strncpy((char *)&info.data[idx], bt_version.version, strlen(bt_version.version));
    idx += strlen(bt_version.version);
    
    info.len = idx;
    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_signal_quality(common_msg_st *msg)
{
    signal_quality_t signal_quality = {0};
    int idx = 0;

    /* 1. 获取小电池信息 */
    int32_t res = swei_get_device_info(SINAL_QUALITY, (void *)&signal_quality, sizeof(signal_quality));    
    if (res != 0)
    {
        log_e("tbox get signal quality failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = TBOX_SIGNAL_STRENGTH_INFORMATION;
    info.data[idx++] = signal_quality.csq;
    info.data[idx++] = signal_quality.rsrp;
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_chg_status(common_msg_st *msg, uint8_t type)
{
    libat_charger_info_t chg_status = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(CHG_STAT, (void *)&chg_status, sizeof(chg_status));    
    if (res != 0)
    {
        log_e("tbox get batt charging status failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_TBOX_BMS_CHARGE;
    info.data[idx++] = type;
    info.data[idx++] = ((chg_status.charge_count) >> 8) & 0xFF;
    info.data[idx++] = ((chg_status.charge_count)) & 0xFF;
    info.data[idx++] = ((chg_status.charge_total_time) >> 24) & 0xFF;
    info.data[idx++] = ((chg_status.charge_total_time) >> 16) & 0xFF;
    info.data[idx++] = ((chg_status.charge_total_time) >> 8) & 0xFF;
    info.data[idx++] = ((chg_status.charge_total_time)) & 0xFF;    
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_econ_info(common_msg_st *msg)
{
    econ_info_t econ_info = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(ECON_INFO, (void *)&econ_info, sizeof(econ_info));    
    if (res != 0)
    {
        log_e("tbox get econ info failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_ELEC_CON_STA;
    info.data[idx++] = ((econ_info.speed) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.speed)) & 0xFF;
    info.data[idx++] = ((econ_info.temp) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.temp)) & 0xFF;
    info.data[idx++] = ((econ_info.torque_volt) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.torque_volt)) & 0xFF;
    info.data[idx++] = ((econ_info.motor_speed) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.motor_speed)) & 0xFF;
    info.data[idx++] = ((econ_info.ride_freq) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.ride_freq)) & 0xFF;
    info.data[idx++] = ((econ_info.bus_volt) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.bus_volt)) & 0xFF;    
    info.data[idx++] = ((econ_info.bus_cur) >> 8) & 0xFF;
    info.data[idx++] = ((econ_info.bus_cur)) & 0xFF;   
    info.data[idx++] = ((econ_info.braking_stat)) & 0xFF;   
    info.data[idx++] = ((econ_info.throttle_volt)) & 0xFF;

    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池充电信息
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_charge_status_info(common_msg_st *msg, uint32_t param)
{
    batt_run_status_info_t batt_run_status_info;
    batt_charge_status_info_t batt_charge_status_info;
    batt_cell_volt_info_t batt_cell_volt_info;
    batt_status_info_t batt_status_info;
    uint16_t status_id = 0;

     /* 1. 获取信息 */
    if(0 == param) {
        status_id = CAN_UPLOAD_TAG_ID_BMS_CHARGE_INFO;
        batt_run_status_info_get((void *)&batt_run_status_info, sizeof(batt_run_status_info_t));
        batt_charge_status_info_get((void *)&batt_charge_status_info, sizeof(batt_charge_status_info_t));
        batt_cell_volt_info_get((void *)&batt_cell_volt_info, sizeof(batt_cell_volt_info_t));
        batt_status_info_get((void *)&batt_status_info, sizeof(batt_status_info_t));
    }else {
        status_id = CAN_UPLOAD_TAG_ID_BMS_BACK_CHARGE_INFO;
        backup_batt_run_status_info_get((void *)&batt_run_status_info, sizeof(batt_run_status_info_t));
        backup_batt_charge_status_info_get((void *)&batt_charge_status_info, sizeof(batt_charge_status_info_t));
        backup_batt_cell_volt_info_get((void *)&batt_cell_volt_info, sizeof(batt_cell_volt_info_t));
        backup_batt_status_info_get((void *)&batt_status_info, sizeof(batt_status_info_t));
    }


    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* data部分转大端 */
    if(batt_charge_status_info.charge_s_valid && (0 == batt_charge_status_info.charge_state) && (batt_run_status_info.current >= 0)) {
        info.data[idx ++] = (batt_run_status_info.current >> 8) & 0xFF; 
        info.data[idx ++] = batt_run_status_info.current & 0xFF; 
    } else {
        info.data[idx ++] = 0; 
        info.data[idx ++] = 0; 
    }

    
    if (batt_charge_status_info.charge_s_valid && (0 == batt_charge_status_info.charge_state) && batt_run_status_info.batt_v_valid) {
        uint16_t batt_voltage = (uint16_t)(batt_run_status_info.batt_voltage * 10);
        info.data[idx ++] = (batt_voltage >> 8) & 0xFF; 
        info.data[idx ++] = batt_voltage & 0xFF; 
    } else {
        info.data[idx ++] = 0;
        info.data[idx ++] = 0; 
    }

    if (batt_run_status_info.temp_valid) {
        info.data[idx ++] = (batt_run_status_info.temperature >> 8) & 0xFF; 
        info.data[idx ++] = batt_run_status_info.temperature & 0xFF; 
    } else {
        info.data[idx ++] = 0;
        info.data[idx ++] = 0; 
    }

    uint16_t batt_total_volt = 0;
    for(int i = 0; i < batt_cell_volt_info.cell_cnt; i++) {
        batt_total_volt += batt_cell_volt_info.cell_volt[i];
    }
    info.data[idx ++] = ((batt_total_volt / 10) >> 8) & 0xFF; 
    info.data[idx ++] = (batt_total_volt / 10) & 0xFF; 
        
    info.data[idx ++] = (batt_status_info.charge_remain_time >> 8) & 0xFF; 
    info.data[idx ++] = batt_status_info.charge_remain_time  & 0xFF; 
    
    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池电芯信息
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_cell_volt_info(common_msg_st *msg, uint32_t param)
{
    batt_cell_volt_info_t batt_cell_volt_info;
    uint16_t status_id = 0;

     /* 1. 获取信息 */
    if(0 == param) {
        status_id = 0x1005;
        batt_cell_volt_info_get((void *)&batt_cell_volt_info, sizeof(batt_cell_volt_info_t));
    }else {
        status_id = 0x100D;
        backup_batt_cell_volt_info_get((void *)&batt_cell_volt_info, sizeof(batt_cell_volt_info_t));
    }


    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* data部分转大端 */
    info.data[idx ++] = 0;
    info.data[idx ++] = 1;  //电芯起始ID固定1,占两个字节

    for(int i = 0; i < batt_cell_volt_info.cell_cnt; i++) {
        info.data[idx ++] = (batt_cell_volt_info.cell_volt[i] >> 8) & 0xFF; 
        info.data[idx ++] = batt_cell_volt_info.cell_volt[i] & 0xFF; 
    }
    
    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池充放电次数
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_charge_cycle_info(common_msg_st *msg, uint32_t param)
{
    batt_charge_status_info_t batt_charge_status_info;

    uint16_t status_id = 0;

     /* 1. 获取信息 */
    if(0 == param) {
        status_id = 0x1006;
        batt_charge_status_info_get((void *)&batt_charge_status_info, sizeof(batt_charge_status_info_t));
    }else {
        status_id = 0x100E;
        backup_batt_charge_status_info_get((void *)&batt_charge_status_info, sizeof(batt_charge_status_info_t));
    }

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* data部分转大端 */
    if(batt_charge_status_info.charge_c_valid) {
        info.data[idx ++] = (batt_charge_status_info.charge_cycle >> 8) & 0xFF; 
        info.data[idx ++] = batt_charge_status_info.charge_cycle & 0xFF; 
    } else {
        info.data[idx ++] = 0;
        info.data[idx ++] = 0;
    }
    
    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池工作状态
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_work_status_info(common_msg_st *msg, uint32_t param)
{
    batt_run_status_info_t batt_run_status_info;
    batt_charge_status_info_t batt_charge_status_info;
    uint16_t status_id = 0;

    /* 1. 获取信息 */
    if(0 == param) {
        status_id = 0x1007;
        batt_run_status_info_get((void *)&batt_run_status_info, sizeof(batt_run_status_info_t));
        batt_charge_status_info_get((void *)&batt_charge_status_info, sizeof(batt_charge_status_info_t));
    }else {
        status_id = 0x100F;
        backup_batt_run_status_info_get((void *)&batt_run_status_info, sizeof(batt_run_status_info_t));
        backup_batt_charge_status_info_get((void *)&batt_charge_status_info, sizeof(batt_charge_status_info_t));
    }


    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* data部分转大端 */
    if(batt_charge_status_info.charge_s_valid && (0 == batt_charge_status_info.charge_state)){
        info.data[idx ++] = 0x1;  
    } else if(batt_run_status_info.discharge_s_valid && (0 == batt_run_status_info.discharge_status)) {
        info.data[idx ++] = 0x0; 
    } else {
        info.data[idx ++] = 0x2;
    }
    
    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_econ_stat(common_msg_st *msg)
{
    econ_stat_t econ_stat = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(ECON_STAT, (void *)&econ_stat, sizeof(econ_stat));    
    if (res != 0)
    {
        log_e("tbox get econ stat failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_ELEC_CON_RUNNING;
    info.data[idx++] = ((econ_stat.pwr_lvl)) & 0xFF;
    info.data[idx++] = ((econ_stat.econ_work_stat)) & 0xFF;
    info.data[idx++] = ((econ_stat.econ_mode)) & 0xFF;
    info.data[idx++] = ((econ_stat.vehicle_stat)) & 0xFF;
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_econ_basic_info(common_msg_st *msg)
{
    econ_basic_info_t econ_basic_info = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(ECON_BASIC_INFO, (void *)&econ_basic_info, sizeof(econ_basic_info));    
    if (res != 0)
    {
        log_e("tbox get econ basic info failed,res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_ELEC_CON_VER;
    info.data[idx++] = econ_basic_info.sn_len;
    strncpy((char *)&info.data[idx], econ_basic_info.sn, econ_basic_info.sn_len);
    idx += econ_basic_info.sn_len;

    info.data[idx++] = econ_basic_info.hw_ver_len;
    strncpy((char *)&info.data[idx], econ_basic_info.hw_ver, econ_basic_info.hw_ver_len);
    idx += econ_basic_info.hw_ver_len;

    info.data[idx++] = econ_basic_info.soft_ver_len;   
    strncpy((char *)&info.data[idx], econ_basic_info.soft_ver, econ_basic_info.soft_ver_len);
    idx += econ_basic_info.soft_ver_len;

    info.data[idx++] = econ_basic_info.eeprom_len;   
    strncpy((char *)&info.data[idx], econ_basic_info.eeprom, econ_basic_info.eeprom_len);
    idx += econ_basic_info.eeprom_len;
    
    info.data[idx++] = (econ_basic_info.wheel_diameter >> 8) & 0xFF;
    info.data[idx++] = econ_basic_info.wheel_diameter & 0xFF;

    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_bike_data1(common_msg_st *msg)
{
    bike_data1_t bike_data1 = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(BIKE_DATA1, (void *)&bike_data1, sizeof(bike_data1));    
    if (res != 0)
    {
        log_e("tbox get bike data1 failed, res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_BIKE_DATA1;
    info.data[idx++] = ((bike_data1.remain_range) >> 8) & 0xFF;
    info.data[idx++] = ((bike_data1.remain_range)) & 0xFF;
    info.data[idx++] = bike_data1.remain_volume;

    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}

int32_t swei_status_get_bike_data2(common_msg_st *msg)
{
    bike_data2_t bike_data2 = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(BIKE_DATA2, (void *)&bike_data2, sizeof(bike_data2));    
    if (res != 0)
    {
        log_e("tbox get bike data2 failed, res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_BIKE_DATA2;
    info.data[idx++] = ((bike_data2.single_range) >> 8) & 0xFF;
    info.data[idx++] = ((bike_data2.single_range)) & 0xFF;
    info.data[idx++] = ((bike_data2.total_range) >> 24) & 0xFF;
    info.data[idx++] = ((bike_data2.total_range) >> 16) & 0xFF;
    info.data[idx++] = ((bike_data2.total_range) >> 8) & 0xFF;
    info.data[idx++] = ((bike_data2.total_range)) & 0xFF;
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_bike_stat(common_msg_st *msg)
{
    bike_stat_t bike_stat = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(BIKE_STAT, (void *)&bike_stat, sizeof(bike_stat));    
    if (res != 0)
    {
        log_e("tbox get bike stat failed, res:%d", res);
        return -EIO;
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_BIKE_STATE;
    info.data[idx++] = bike_stat.ride_stat;
    info.data[idx++] = bike_stat.elock_stat;
    info.data[idx++] = bike_stat.charger_stat;
    info.data[idx++] = bike_stat.tailight_stat;
    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


int32_t swei_status_get_fault_code(common_msg_st *msg, uint32_t i)
{
    co_fault_code_t fault_code_tbl[FAULT_NUM] = {0};
    int idx = 0;

    int32_t res = swei_get_device_info(FAULT_CODE, (void *)fault_code_tbl, ARRAY_COUNT(fault_code_tbl));    
    if (res != 0)
    {
        log_e("tbox get bike fault code failed, res:%d", res);
    }  

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info = {0};

    info.status_id = CAN_UPLOAD_TAG_ID_BMS_WARNING_CODE;

    if (!is_array_zero(fault_code_tbl[i].code, ARRAY_COUNT(fault_code_tbl[i].code))) {
        /* 故障类型 */
        info.data[idx++] = i+1;
        /* 故障码 */
        for (int j = 0; j < ARRAY_COUNT(fault_code_tbl[i].code); j++) {
            if (0 != fault_code_tbl[i].code[j]) {
                /* 主电和副电池 */
                if (1 == i+1 || 2 == i+1)
                    info.data[idx++] = fault_code_tbl[i].code[j] - 79;
                else
                    info.data[idx++] = fault_code_tbl[i].code[j];
            }
                
        }
    } else {
        info.data[idx++] = i+1;
    }

    info.len = idx;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池基本信息
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_basic_info(common_msg_st *msg, uint32_t param)
{
    batt_version_t batt_version;
    char batt_sn[32] = {0};
    
    uint16_t status_id = 0;
    
     /* 1. 获取信息 */
    if(0 == param) {
        status_id = CAN_UPLOAD_TAG_ID_BMS_INFO;
        batt_seqnum_get((uint8_t *)batt_sn, sizeof(batt_sn));
    }else {
        status_id = CAN_UPLOAD_TAG_ID_BMS_BACK_INFO;
        backup_batt_seqnum_get((uint8_t *)batt_sn, sizeof(batt_sn));
    }

    batt_version_get((uint8_t *)&batt_version, sizeof(batt_version_t));

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* data部分转大端 */
    char sn_len;
    sn_len = strlen((void *)(batt_sn));

    if(sn_len > 0){
        info.data[idx ++] = sn_len;
        memcpy(info.data + idx, batt_sn, sn_len);
        idx += sn_len;
        
    } else {
        info.data[idx ++] = 0;
    }

    char sw_len = strlen(batt_version.sw_ver_str);
    info.data[idx ++] = sw_len;
    memcpy(info.data + idx, batt_version.sw_ver_str, sw_len);
    idx += sw_len;

    char hw_len = strlen(batt_version.hw_ver_str);
    info.data[idx ++] = hw_len;
    memcpy(info.data + idx, batt_version.hw_ver_str, hw_len);
    idx += hw_len;

    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池容量信息
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_capacity_info(common_msg_st *msg, uint32_t param)
{
    batt_capacity_info_t batt_capacity_info;
    uint16_t status_id = 0;

     /* 1. 获取信息 */
    if(0 == param) {
        status_id = 0x1002;
        batt_capacity_info_get((void *)&batt_capacity_info, sizeof(batt_capacity_info_t));
    }else {
        status_id = 0x100A;
        backup_batt_capacity_info_get((void *)&batt_capacity_info, sizeof(batt_capacity_info_t));
    }


    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* soc */
    if (batt_capacity_info.is_soc_valid)
        info.data[idx ++] = batt_capacity_info.soc; 
    else 
        info.data[idx ++] = 0; 

    /* soh */
    if (batt_capacity_info.is_soh_valid)
        info.data[idx ++] = batt_capacity_info.soh; 
    else
        info.data[idx ++] = 0; 

    if(batt_capacity_info.remain_c_valid)
        idx += bigending2buf(info.data + idx, batt_capacity_info.remain_capacity * 10);
    else
        idx += bigending2buf(info.data + idx, 0);

    if(batt_capacity_info.full_c_valid)
        idx += bigending2buf(info.data + idx, batt_capacity_info.full_capacity * 10);
    else
        idx += bigending2buf(info.data + idx, 0);

    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


/**
 * @description: 获取电池放电状态信息
 * @param {common_msg_st} *msg - output
 * @param {uint8_t} param - 电池类型
 * @return {*}
 * @Date: 
 * @modification:
 */
int32_t swei_status_get_batt_discharge_status_info(common_msg_st *msg, uint32_t param)
{
    batt_run_status_info_t batt_run_status_info;
    batt_cell_volt_info_t batt_cell_volt_info;
    uint16_t status_id = 0;

     /* 1. 获取信息 */
    if(0 == param) {
        status_id = 0x1003;
        batt_run_status_info_get((void *)&batt_run_status_info, sizeof(batt_run_status_info_t));
        batt_cell_volt_info_get((void *)&batt_cell_volt_info, sizeof(batt_cell_volt_info_t));
    }else {
        status_id = 0x100B;
        backup_batt_run_status_info_get((void *)&batt_run_status_info, sizeof(batt_run_status_info_t));
        backup_batt_cell_volt_info_get((void *)&batt_cell_volt_info, sizeof(batt_cell_volt_info_t));
    }

    /* 2. 转info结构为common_msg_st */
    UPLOAD_INFO_ST info;
    int32_t idx = 0;

    /* data部分转大端 */
    if (batt_run_status_info.discharge_s_valid && (0 == batt_run_status_info.discharge_status) && (batt_run_status_info.current <= 0)) {
        info.data[idx ++] = (abs(batt_run_status_info.current) >> 8) & 0xFF; 
        info.data[idx ++] = abs(batt_run_status_info.current) & 0xFF; 
    } else {
        info.data[idx ++] = 0; 
        info.data[idx ++] = 0; 
    }

    if (batt_run_status_info.temp_valid) {
        info.data[idx ++] = (batt_run_status_info.temperature >> 8) & 0xFF; 
        info.data[idx ++] = batt_run_status_info.temperature & 0xFF; 
    } else {
        info.data[idx ++] = 0;
        info.data[idx ++] = 0; 
    }

    uint16_t batt_total_volt = 0;
    for(int i = 0; i < batt_cell_volt_info.cell_cnt; i++) {
        batt_total_volt += batt_cell_volt_info.cell_volt[i];
    }
    info.data[idx ++] = ((batt_total_volt / 10) >> 8) & 0xFF; 
    info.data[idx ++] = (batt_total_volt / 10) & 0xFF;

    info.len = idx;
    info.status_id = status_id;

    // 3. 转化info为msg数据结构
    int32_t ret = 0;
    if ((ret = info2msg(info, msg)) > 0) {
        msg->msg_len += ret;
        return 0;
    }

    return ret;
}


#include "FreeRTOS.h"
#include "queue.h"


#define EVENT_MAX_SIZE (128)
QueueHandle_t event_queue = NULL;


/**
 * @brief 设备状态更新函数
 * @param  type             My Param doc
 */
int32_t swei_status_event_update(status_event_id id, uint32_t arg)
{
    swei_status_evt_t evt = {
        .id = id,
        .arg = arg,
        .work_id = swei_get_workid(),
    };

    // push event queue to event group
    if (NULL == event_queue)
    {
        event_queue = xQueueCreate(EVENT_MAX_SIZE, sizeof(swei_status_evt_t));
        if(NULL == event_queue)      
        {
            log_e("create queue for cache failed!\r\n");
            return -EIO;
        }
    }

    if(NULL == event_queue)
        return -EIO;

    if(pdPASS == xQueueSendToBack(event_queue, &evt, 0))
    {
        return 0;
    }

    return -EIO;
}

/**
 * @brief 事件转msg结构
 * @param  evt              状态事件
 * @param  msg              
 * @return int32_t 0 - succ
 */
static int32_t event2msg(swei_status_evt_t evt, common_msg_st *msg) 
{
    int32_t ret = 0;

    switch(evt.id) {   
        /* 电池基本信息(0x1001) */
        case CAN_UPLOAD_TAG_ID_BMS_INFO:
        {
            ret = swei_status_get_batt_basic_info(msg, 0);
        }break;

        /* 电池容量(0x1002) */
        case CAN_UPLOAD_TAG_ID_BMS_CAPACITY_INFO:
        {
            ret = swei_status_get_batt_capacity_info(msg, 0);
        }break;        

        /* 放电相关信息（0x1003）*/
        case CAN_UPLOAD_TAG_ID_BMS_DISCHARGE_INFO:
        {
            ret = swei_status_get_batt_discharge_status_info(msg, 0);
        }break;        

        /* 充电相关信息(0x1004) */
        case CAN_UPLOAD_TAG_ID_BMS_CHARGE_INFO:
        {
            //if(evt.arg == CHARGE_START)
            //    ret = swei_status_get_charger_info(msg, CHARGE_START);
            //if(evt.arg == CHARGE_FINISH)
            //    ret = swei_status_get_charger_info(msg, CHARGE_FINISH);
            ret = swei_status_get_batt_charge_status_info(msg, 0);
        }break;

        /* （0x1005） */
        case CAN_UPLOAD_TAG_ID_BMS_CELL_VOL_INFO1:
        {
            ret = swei_status_get_batt_cell_volt_info(msg, 0);
        }break;

        /* （0x1006） */
        case CAN_UPLOAD_TAG_ID_BMS_CYCLE_TIMES:
        {
            ret = swei_status_get_batt_charge_cycle_info(msg, 0);
        }break;

        /* （0x1007） */
        case CAN_UPLOAD_TAG_ID_BMS_WORKING_STA:
        {
            ret = swei_status_get_batt_work_status_info(msg, 0);
        }break;        

        /* （0x1009） */
        case CAN_UPLOAD_TAG_ID_BMS_BACK_INFO:
        {
            ret = swei_status_get_batt_basic_info(msg, 1);
        }break;

        /* （0x100A） */
        case CAN_UPLOAD_TAG_ID_BMS_BACK_CAPACITY_INFO:
        {
            ret = swei_status_get_batt_capacity_info(msg, 1);
        }break;

        /* (0X100B) */
        case CAN_UPLOAD_TAG_ID_BMS_BACK_DISCHARGE_INFO:
        {
            ret = swei_status_get_batt_discharge_status_info(msg, 1);
        }break;        

        case CAN_UPLOAD_TAG_ID_BMS_BACK_CHARGE_INFO:
        {
            ret = swei_status_get_batt_charge_status_info(msg, 1);
        }break;

        /* (0X100D) */
        case CAN_UPLOAD_TAG_ID_BMS_BACK_CELL_VOL_INFO1:
        {
            ret = swei_status_get_batt_cell_volt_info(msg, 1);
        }break;

        /* (0X100E) */
        case CAN_UPLOAD_TAG_ID_BMS_BACK_CYCLE_TIMES:
        {
            ret = swei_status_get_batt_charge_cycle_info(msg, 1);
        }break;

        /* (0X100F) */
        case CAN_UPLOAD_TAG_ID_BMS_BACK_WORKING_STA:
        {
            ret = swei_status_get_batt_work_status_info(msg, 1);
        }break;

        /* 设备信息 (0X5001) */
        case CAN_UPLOAD_DEV_INFO:
        {
            ret = swei_status_get_dev_info(msg);
        }break;

        /* 状态信息 (0x5002) */
        case CAN_UPLOAD_STATUS_INFO:
        {
            ret = swei_status_get_tbox_stat(msg);
        }break;

        /* 设备版本信息 (0x5003) */
        case TBOX_UPLOAD_DEV_VERSION:
        {
            ret = swei_status_get_version_info(msg);
        }break;

        /* tbox信号强度信息 (0x5004) */
        case TBOX_SIGNAL_STRENGTH_INFORMATION:
        {
            ret = swei_status_get_signal_quality(msg);
        }break;

        /* Tbox电池信息（0x1010) */
        case CAN_UPLOAD_TAG_ID_TBOX_BMS_INFO:
        {
            ret = swei_status_get_batt_info(msg);
        }break;

        /* Tbox电池充电事件信息（0x1011） */
        case CAN_UPLOAD_TAG_ID_TBOX_BMS_CHARGE:
        {
            if (evt.arg == CHARGE_START)
                ret = swei_status_get_chg_status(msg, CHARGE_START);
            if (evt.arg == CHARGE_FINISH)
                ret = swei_status_get_chg_status(msg, CHARGE_FINISH);            
        }break;

        /* 电控状态信息（0x2001） */
        case CAN_UPLOAD_TAG_ID_ELEC_CON_STA:
        {
            ret = swei_status_get_econ_info(msg);
        }break;

        /* 电控运行信息（0x2002 ） */
        case CAN_UPLOAD_TAG_ID_ELEC_CON_RUNNING:
        {
            ret = swei_status_get_econ_stat(msg);
        }break;      

        /* 电控基本信息（0x2003）*/
        case CAN_UPLOAD_TAG_ID_ELEC_CON_VER:
        {
            ret = swei_status_get_econ_basic_info(msg);
        }break;   

        /* 车况数据1（0x3001）*/
        case CAN_UPLOAD_TAG_ID_BIKE_DATA1:
        {
            ret = swei_status_get_bike_data1(msg);
        }break;    

         /* 车况数据2（0x3002）*/
        case CAN_UPLOAD_TAG_ID_BIKE_DATA2:
        {
            ret = swei_status_get_bike_data2(msg);
        }break;        

         /* 车辆状态（0x3003）*/
        case CAN_UPLOAD_TAG_ID_BIKE_STATE:
        {
            ret = swei_status_get_bike_stat(msg);
        }break;  

        /* 故障码（0x4001） */
        case CAN_UPLOAD_TAG_ID_BMS_WARNING_CODE:
        {
            ret = swei_status_get_fault_code(msg, evt.arg);
        }break;

        default:
            return -EIO;
    }

    return ret;
}

/**
 * @brief 事件出队并调用swei_status_get_xx api转化为common_msg_st结构体类型，供上层调用
 * @param  msg 存放msg待发送消息
 * @return int32_t 0 - succ
 */
int32_t swei_status_event_peek(common_msg_st *msg)
{
    #define MAX_EVENT_CNT (10)
    uint32_t evt_cnt = 0;
    uint32_t last_evt_work_id = 0;

    
    swei_status_lock();
    swei_status_unlock();
    

    // check and create the event queue
    if (NULL == event_queue)
    {
        event_queue = xQueueCreate(EVENT_MAX_SIZE, sizeof(swei_status_evt_t));
        if(NULL == event_queue)      
        {
            log_e("create queue for cache failed!\r\n");
            return -EIO;
        }
    }

    // assert the evet queue param
    if(NULL == event_queue)
        return -EIO;

    do {
        // pop event queue, and call swei_status_get_xxx api to get msg datatype;
        // than send out with tcp api; 
        swei_status_evt_t evt = {
            .id = CAN_UPLOAD_NONE,
            .arg = 0,
            .work_id = 0,
        };

        // 先看看workid是否发生变更
        if(pdPASS != xQueuePeek(event_queue, &evt, 0)) {
            break;
        }

        if (last_evt_work_id != 0 && last_evt_work_id != evt.work_id) {
            break;
        }

        // 出队status状态报文
        if(pdPASS != xQueueReceive(event_queue, &evt, 0)) {
            break;
        }

        /* 事件入msg */
        if (0 == event2msg(evt, msg)) {
            evt_cnt++;
            if (evt_cnt >= MAX_EVENT_CNT) {
                break;
            }

            last_evt_work_id = evt.work_id;
        } else {
            /* 事件转化失败 */
            log_e("event2msg failed, event id = %04X!\r\n", evt.id);
            break;
        }
    } while(1);

    if (msg->msg_len > 0) {
        return 0;
    }

    return -EAGAIN;
}



#include "service/include/swei_config.h"
utils_time_t rsrp_upload_timer = {0};
/**
 * @brief  定期rsrp消息
 * @param  msg              My Param doc
 * @return int32_t 
 */
int32_t swei_status_push_rsrp(void)
{
    int32_t sleep_time = 0;

    // 2. 判断是否达到上报时间
    sleep_time = swei_config_rtp_intval_update(REPORT_RSRP_SIGNAL);
    if(0 == sleep_time) { /* 0 表示改模式下未配置上报 */
        return -EIO;
    }

    if(!utils_time_is_expired(&rsrp_upload_timer))
    {
        return -EIO;
    }

    /* 触发信号强度上报 */
    swei_status_event_update(TBOX_SIGNAL_STRENGTH_INFORMATION, 0);

    utils_time_countdown_ms(&rsrp_upload_timer, sleep_time * 1000);
    log_i(">>>> send rsrp info! <<<< \r\n");

    return 0;
}


utils_time_t batt_upload_timer = {0};
/**
 * @brief 定期小电池电量信息
 * @param  msg              My Param doc
 * @return int32_t 
 */
int32_t swei_status_push_libatt(void)
{
    int32_t sleep_time = 0;
    static uint8_t last_charger_status = 0;

    if(libatt_charger_status_get() != last_charger_status) {    /* 充电状态变化 */
        last_charger_status = libatt_charger_status_get();
        swei_status_event_update(CAN_UPLOAD_TAG_ID_TBOX_BMS_CHARGE, 0);
    }

    // 2. 判断是否达到上报时间
    sleep_time = swei_config_rtp_intval_update(REPORT_TBOX_BATT);

    /* 低功耗下，要上报前的十秒钟查询一下小电池状态 */
    if (WORK_MODE_SLEEP == misc_get_work_mode() && 10 *1000 == utils_time_left(&batt_upload_timer)) {
        uint16_t libatt_key = LBATT_STATUS_INFO;
        co_key_add(&libatt_key, 1);
    }

    if(!utils_time_is_expired(&batt_upload_timer))
    {
        return -EIO;
    }

    /* 触发小电池信息上报 */
    swei_status_event_update(CAN_UPLOAD_TAG_ID_TBOX_BMS_INFO, 0);

    utils_time_countdown_ms(&batt_upload_timer, sleep_time * 1000);
    log_i(">>>> send batt info! <<<< \r\n");
    
    return 0;
}


utils_time_t can_info_type1_rpt_timer = {0};
/**
 * @brief 定期10s的can数据1
 * @param  msg              My Param doc
 * @return int32_t 
 */
int32_t swei_status_push_caninfo_type1(void)
{
    int32_t sleep_time = 0;

    // 2. 判断是否达到上报时间
    sleep_time = swei_config_rtp_intval_update(REPORT_CAN_INFO_TYPE1);
    if(0 == sleep_time) { /* 0 表示改模式下未配置上报 */
        return -EIO;
    }

    if(!utils_time_is_expired(&can_info_type1_rpt_timer))
    {
        return -EIO;
    }

    /**
     * @brief 禁止status出队
     */
    swei_status_lock();
    /**
     * @brief 主电池
     */
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_WORKING_STA, 0);
    /**
     * @brief 副电池工作状态
     */
    if (is_backup_batt_insert())
        swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_BACK_WORKING_STA, 0);
    /**
     * @brief 车况数据
     */
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BIKE_DATA2, 0);
    /**
     * @brief 允许status出队
     */
    swei_status_unlock();

    utils_time_countdown_ms(&can_info_type1_rpt_timer, sleep_time * 1000);
    log_i(">>>> send can info type 1! <<<< \r\n");
    
    return 0;
}


utils_time_t can_info_type2_rpt_timer = {0};
/**
 * @brief 定期30s的can数据2
 * @param  msg              My Param doc
 * @return int32_t 
 */
int32_t swei_status_push_caninfo_type2(void)
{
    int32_t sleep_time = 0;

    // 2. 判断是否达到上报时间
    sleep_time = swei_config_rtp_intval_update(REPORT_CAN_INFO_TYPE2);
    if(0 == sleep_time) { /* 0 表示改模式下未配置上报 */
        return -EIO;
    }

    if(!utils_time_is_expired(&can_info_type2_rpt_timer))
    {
        return -EIO;
    }
    /**
     * @brief 禁止status出队
     */

    swei_status_lock();

    /**
     * @brief 主电池
     */
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_CAPACITY_INFO, 0);
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_DISCHARGE_INFO, 0);
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_CHARGE_INFO, 0);
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_CELL_VOL_INFO1, 0);

    /**
     * @brief 副电池
     */
    if (is_backup_batt_insert()) {
        swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_BACK_CAPACITY_INFO, 0);
        swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_BACK_DISCHARGE_INFO, 0);
        /* 上报备电充电状态信息（0x100C） */
        swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_BACK_CHARGE_INFO, 0);
        swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_BACK_CELL_VOL_INFO1, 0);
    }

    /**
     * @brief 电控信息
     */
    swei_status_event_update(CAN_UPLOAD_TAG_ID_ELEC_CON_STA, 0);
    /**
     * @brief 车况数据
     */
    swei_status_event_update(CAN_UPLOAD_TAG_ID_BIKE_DATA1, 0);
    /**
     * @brief 允许status出队
     */
    swei_status_unlock();

    utils_time_countdown_ms(&can_info_type2_rpt_timer, sleep_time * 1000);
    log_i(">>>> send can info type 2! <<<< \r\n");
    
    return 0;
}

#include "FreeRTOS.h"
#include "task.h"

SemaphoreHandle_t sta_lock = NULL;
/**
 * @brief 禁止状态报文出队
 */
void swei_status_lock(void)
{
    if (NULL == sta_lock) {
        sta_lock = xSemaphoreCreateMutex();
        if (NULL == sta_lock)
            return;
    }
    xSemaphoreTake(sta_lock, portMAX_DELAY);
}

/**
 * @brief 允许状态报文出队
 */
void swei_status_unlock(void)
{
    if (NULL == sta_lock) {
        sta_lock = xSemaphoreCreateMutex();
        if (NULL == sta_lock)
            return;
    }
    xSemaphoreGive(sta_lock);
}

// #include "lettershell/shell.h"
// /**
//  * @brief 
//  * @return int32_t 
//  */
// int32_t swei_status_test(void)
// {
//     swei_status_event_update(CAN_UPLOAD_TAG_ID_BMS_INFO, 0);

//     return 0;
// }
// SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC), swei_status_test, swei_status_test, trigger status event send process);
